﻿using Autofac;
using Autofac.Core;
using Autofac.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace ManaMaple.Autofac
{
    /// <summary>
    ///  Autofac扩展
    /// </summary>
    public static class AutofacService
    {
        public static void AutofacModules(this IHostBuilder hostBuilder, IEnumerable<Assembly> assemblies)
        {
            hostBuilder.UseServiceProviderFactory(new AutofacServiceProviderFactory())
                .ConfigureContainer<ContainerBuilder>((contest, builder) =>
                {
                    RegisterModules(builder, assemblies);
                });
        }

        /// <summary>
        /// Autofac程序集扫描注入
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="assemblies"></param>
        /// <exception cref="Exception"></exception>
        private static void RegisterModules(ContainerBuilder builder, IEnumerable<Assembly> assemblies)
        {
            foreach (var moduleType in GetModuleTypes(assemblies))
            {
                builder.RegisterModule((IModule)Activator.CreateInstance(moduleType));
            }
        }
        /// <summary>
        /// 使用接口
        /// </summary>
        /// <param name="Assemblies"></param>
        /// <returns></returns>
        /// <exception cref="Exception?"></exception>
        private static IEnumerable<Type> GetModuleTypes(IEnumerable<Assembly> Assemblies)
        {
            foreach (var assembly in Assemblies)
            {
                IEnumerable<Type> types;
                try
                {
                    types = assembly.GetTypes();
                }
                catch (ReflectionTypeLoadException e)
                {
                    throw e.LoaderExceptions.First();
                }
                foreach (var type in types)
                {
                    //if (type.IsClass && !type.IsAbstract && type.GetInterface(typeof(IInjectionModule).FullName) != null)
                    if (type.IsClass && type.GetInterface(typeof(IInjectionModule).FullName) != null)
                    {
                        yield return type;
                    }
                }
            }
        }
        /// <summary>
        /// 使用特性
        /// </summary>
        /// <param name="Assemblies"></param>
        /// <returns></returns>
        /// <exception cref="Exception?"></exception>
        private static IEnumerable<Type> GetModuleTypesAttribute(IEnumerable<Assembly> Assemblies)
        {
            foreach (var assembly in Assemblies)
            {
                IEnumerable<Type> types;
                try
                {
                    types = assembly.GetTypes();
                }
                catch (ReflectionTypeLoadException e)
                {
                    throw e.LoaderExceptions.First();
                }
                foreach (var type in types)
                {
                    //使用特性 来判断模块是否可以注入
                    var injectionModuleAttribute = type.GetCustomAttribute<InjectionModuleAttribute>(true);
                    if (type.IsClass && !type.IsAbstract && injectionModuleAttribute != null && injectionModuleAttribute.IsInjection)
                    {
                        yield return type;
                    }
                }
            }
        }
    }
}
